using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SeataNet.Core.Common;
using SeataNet.Core.Context;
using SeataNet.Core.Interceptor;
using SeataNet.Core.RPC;
using SeataNet.Core.Saga;
using SeataNet.Core.Transaction;

namespace SeataNet.Core.Saga
{
    /// <summary>
    /// Saga步骤结果
    /// </summary>
    public class SagaStepResult
    {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; set; }
        
        /// <summary>
        /// 结果数据
        /// </summary>
        public object? Data { get; set; }
        
        /// <summary>
        /// 异常信息
        /// </summary>
        public Exception? Exception { get; set; }
        
        /// <summary>
        /// 步骤上下文
        /// </summary>
        public SagaStepContext? StepContext { get; set; }
    }
    /// <summary>
    /// Saga事务拦截器
    /// </summary>
    public class SagaTransactionInterceptor : IInterceptor
    {
        private readonly ILogger<SagaTransactionInterceptor> _logger;
        private readonly IServiceProvider _serviceProvider;
        private readonly ISagaTransactionManager _sagaTransactionManager;
        private readonly ITransactionManager _transactionManager;

        public SagaTransactionInterceptor(
            ILogger<SagaTransactionInterceptor> logger,
            IServiceProvider serviceProvider,
            ISagaTransactionManager sagaTransactionManager,
            ITransactionManager transactionManager)
        {
            _logger = logger;
            _serviceProvider = serviceProvider;
            _sagaTransactionManager = sagaTransactionManager;
            _transactionManager = transactionManager;
        }

        public void Intercept(IInvocation invocation)
        {
            var method = invocation.Method;
            var attributes = method.GetCustomAttributes<SagaTransactionalAttribute>(true).ToList();
            
            if (attributes.Count == 0)
            {
                // 检查类级别的属性
                attributes = invocation.TargetType.GetTypeInfo()
                    .GetCustomAttributes<SagaTransactionalAttribute>(true)
                    .ToList();
            }

            if (attributes.Count == 0)
            {
                // 没有Saga事务注解，直接执行
                invocation.Proceed();
                return;
            }

            var attribute = attributes[0];
            var sagaContext = RootContext.GetSagaTransactionContext();
            
            // 如果已经在Saga事务中，直接执行
            if (sagaContext != null)
            {
                invocation.Proceed();
                return;
            }

            // 开始新的Saga事务
            BeginSagaTransaction(invocation, attribute);
        }

        private void BeginSagaTransaction(IInvocation invocation, SagaTransactionalAttribute attribute)
        {
            var xid = _transactionManager.Begin(null, attribute.Timeout);
            var sagaContext = new SagaTransactionContext
            {
                Xid = xid,
                Status = SagaTransactionStatus.Active,
                StartTime = DateTime.UtcNow,
                Timeout = attribute.Timeout,
                CompensationMethod = attribute.CompensationMethod,
                RetryPolicy = attribute.RetryPolicy,
                SagaName = attribute.SagaName ?? invocation.TargetType.Name
            };

            RootContext.Bind(xid);
            RootContext.BindBranchType(Common.TransactionConstants.BRANCH_TYPE_SAGA);
            RootContext.Bind(sagaContext);

            try
            {
                // 执行业务方法
                invocation.Proceed();
                
                // 提交Saga事务
                _sagaTransactionManager.Commit(xid);
                sagaContext.Status = SagaTransactionStatus.Committed;
                sagaContext.EndTime = DateTime.UtcNow;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Saga transaction execution failed, XID: {Xid}", xid);
                
                try
                {
                    // 回滚Saga事务
                    _sagaTransactionManager.Rollback(xid);
                    sagaContext.Status = SagaTransactionStatus.RolledBack;
                    sagaContext.EndTime = DateTime.UtcNow;
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, "Saga transaction rollback failed, XID: {Xid}", xid);
                    sagaContext.Status = SagaTransactionStatus.Failed;
                    sagaContext.EndTime = DateTime.UtcNow;
                }
                
                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
                RootContext.UnbindBranchType();
                RootContext.UnbindSagaContext();
            }
        }
    }

    /// <summary>
    /// Saga事务切面
    /// </summary>
    public class SagaTransactionAspect
    {
        private readonly ILogger<SagaTransactionAspect> _logger;
        private readonly ISagaTransactionManager _sagaTransactionManager;
        private readonly ITransactionManager _transactionManager;

        public SagaTransactionAspect(
            ILogger<SagaTransactionAspect> logger,
            ISagaTransactionManager sagaTransactionManager,
            ITransactionManager transactionManager)
        {
            _logger = logger;
            _sagaTransactionManager = sagaTransactionManager;
            _transactionManager = transactionManager;
        }

        /// <summary>
        /// 环绕通知
        /// </summary>
        public object Surround(ProceedingJoinPoint joinPoint, SagaTransactionalAttribute attribute)
        {
            var sagaContext = RootContext.GetSagaTransactionContext();
            
            // 如果已经在Saga事务中，直接执行
            if (sagaContext != null)
            {
                return joinPoint.Proceed();
            }

            // 开始新的Saga事务
            var xid = _transactionManager.Begin(null, attribute.Timeout);
            var newSagaContext = new SagaTransactionContext
            {
                Xid = xid,
                Status = SagaTransactionStatus.Active,
                StartTime = DateTime.UtcNow,
                Timeout = attribute.Timeout,
                CompensationMethod = attribute.CompensationMethod,
                RetryPolicy = attribute.RetryPolicy,
                SagaName = attribute.SagaName ?? joinPoint.Target.GetType().Name
            };

            RootContext.Bind(xid);
            RootContext.BindBranchType(Common.TransactionConstants.BRANCH_TYPE_SAGA);
            RootContext.Bind(newSagaContext);

            try
            {
                // 执行业务方法
                var result = joinPoint.Proceed();
                
                // 提交Saga事务
                _sagaTransactionManager.Commit(xid);
                newSagaContext.Status = SagaTransactionStatus.Committed;
                newSagaContext.EndTime = DateTime.UtcNow;
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Saga transaction execution failed, XID: {Xid}", xid);
                
                try
                {
                    // 回滚Saga事务
                    _sagaTransactionManager.Rollback(xid);
                    newSagaContext.Status = SagaTransactionStatus.RolledBack;
                    newSagaContext.EndTime = DateTime.UtcNow;
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, "Saga transaction rollback failed, XID: {Xid}", xid);
                    newSagaContext.Status = SagaTransactionStatus.Failed;
                    newSagaContext.EndTime = DateTime.UtcNow;
                }
                
                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
                RootContext.UnbindBranchType();
                RootContext.UnbindSagaContext();
            }
        }
    }

    /// <summary>
    /// Saga事务模板
    /// </summary>
    public class SagaTransactionTemplate
    {
        private readonly ILogger<SagaTransactionTemplate> _logger;
        private readonly ISagaTransactionManager _sagaTransactionManager;
        private readonly ITransactionManager _transactionManager;

        public SagaTransactionTemplate(
            ILogger<SagaTransactionTemplate> logger,
            ISagaTransactionManager sagaTransactionManager,
            ITransactionManager transactionManager)
        {
            _logger = logger;
            _sagaTransactionManager = sagaTransactionManager;
            _transactionManager = transactionManager;
        }

        /// <summary>
        /// 在Saga事务中执行操作
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="action">要执行的操作</param>
        /// <param name="sagaName">Saga名称</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        /// <param name="compensationMethod">补偿方法</param>
        /// <param name="retryPolicy">重试策略</param>
        /// <returns>操作结果</returns>
        public T Execute<T>(
            Func<T> action,
            string? sagaName = null,
            int timeout = 60000,
            string? compensationMethod = null,
            string? retryPolicy = null)
        {
            var sagaContext = RootContext.GetSagaTransactionContext();
            
            // 如果已经在Saga事务中，直接执行
            if (sagaContext != null)
            {
                return action();
            }

            // 开始新的Saga事务
            var xid = _transactionManager.Begin(null, timeout);
            var newSagaContext = new SagaTransactionContext
            {
                Xid = xid,
                Status = SagaTransactionStatus.Active,
                StartTime = DateTime.UtcNow,
                Timeout = timeout,
                CompensationMethod = compensationMethod,
                RetryPolicy = retryPolicy,
                SagaName = sagaName ?? "SagaTransaction"
            };

            RootContext.Bind(xid);
            RootContext.BindBranchType(Common.TransactionConstants.BRANCH_TYPE_SAGA);
            RootContext.Bind(newSagaContext);

            try
            {
                // 执行业务方法
                var result = action();
                
                // 提交Saga事务
                _sagaTransactionManager.Commit(xid);
                newSagaContext.Status = SagaTransactionStatus.Committed;
                newSagaContext.EndTime = DateTime.UtcNow;
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Saga transaction execution failed, XID: {Xid}", xid);
                
                try
                {
                    // 回滚Saga事务
                    _sagaTransactionManager.Rollback(xid);
                    newSagaContext.Status = SagaTransactionStatus.RolledBack;
                    newSagaContext.EndTime = DateTime.UtcNow;
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, "Saga transaction rollback failed, XID: {Xid}", xid);
                    newSagaContext.Status = SagaTransactionStatus.Failed;
                    newSagaContext.EndTime = DateTime.UtcNow;
                }
                
                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
                RootContext.UnbindBranchType();
                RootContext.UnbindSagaContext();
            }
        }

        /// <summary>
        /// 在Saga事务中执行操作（无返回值）
        /// </summary>
        /// <param name="action">要执行的操作</param>
        /// <param name="sagaName">Saga名称</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        /// <param name="compensationMethod">补偿方法</param>
        /// <param name="retryPolicy">重试策略</param>
        public void Execute(
            Action action,
            string? sagaName = null,
            int timeout = 60000,
            string? compensationMethod = null,
            string? retryPolicy = null)
        {
            Execute(() => { action(); return true; }, sagaName, timeout, compensationMethod, retryPolicy);
        }
    }

    /// <summary>
    /// Saga事务注解
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class SagaTransactionalAttribute : Attribute
    {
        /// <summary>
        /// 超时时间（毫秒）
        /// </summary>
        public int Timeout { get; set; } = 60000;

        /// <summary>
        /// Saga名称
        /// </summary>
        public string? SagaName { get; set; }

        /// <summary>
        /// 补偿方法
        /// </summary>
        public string? CompensationMethod { get; set; }

        /// <summary>
        /// 重试策略
        /// </summary>
        public string? RetryPolicy { get; set; }
    }

    /// <summary>
    /// Saga步骤注解
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class SagaStepAttribute : Attribute
    {
        /// <summary>
        /// 步骤名称
        /// </summary>
        public string StepName { get; set; } = string.Empty;

        /// <summary>
        /// 补偿方法名
        /// </summary>
        public string CompensationMethod { get; set; } = string.Empty;

        /// <summary>
        /// 步骤顺序
        /// </summary>
        public int Order { get; set; } = 0;

        /// <summary>
        /// 是否为可选步骤
        /// </summary>
        public bool IsOptional { get; set; } = false;

        /// <summary>
        /// 重试次数
        /// </summary>
        public int RetryCount { get; set; } = 3;

        /// <summary>
        /// 重试间隔（毫秒）
        /// </summary>
        public int RetryInterval { get; set; } = 1000;
    }

    /// <summary>
    /// Saga服务基类
    /// </summary>
    public abstract class SagaServiceBase
    {
        protected readonly ILogger _logger;

        protected SagaServiceBase(ILogger logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 执行Saga步骤
        /// </summary>
        /// <param name="stepName">步骤名称</param>
        /// <param name="executeAction">执行动作</param>
        /// <param name="compensateAction">补偿动作</param>
        /// <param name="retryCount">重试次数</param>
        /// <param name="retryInterval">重试间隔</param>
        /// <returns>步骤结果</returns>
        protected async Task<SagaStepResult> ExecuteStepAsync(
            string stepName,
            Func<Task<object>> executeAction,
            Func<object, Task> compensateAction,
            int retryCount = 3,
            int retryInterval = 1000)
        {
            var sagaContext = RootContext.GetSagaTransactionContext();
            if (sagaContext == null)
            {
                throw new InvalidOperationException("Not in a Saga transaction context");
            }

            var stepContext = new SagaStepContext
            {
                StepId = Guid.NewGuid().ToString(),
                StepName = stepName,
                Status = SagaStepStatus.Active,
                StartTime = DateTime.UtcNow,
                RetryCount = retryCount,
                RetryInterval = retryInterval
            };

            sagaContext.Steps.Add(stepContext);

            try
            {
                // 执行步骤
                var result = await executeAction();
                
                stepContext.Status = SagaStepStatus.Completed;
                stepContext.EndTime = DateTime.UtcNow;
                stepContext.Result = result;

                // 注册补偿动作
                if (compensateAction != null)
                {
                    stepContext.CompensationAction = async (data) => await compensateAction(data);
                }

                return new SagaStepResult
                {
                    Success = true,
                    Data = result,
                    StepContext = stepContext
                };
            }
            catch (Exception ex)
            {
                stepContext.Status = SagaStepStatus.Failed;
                stepContext.EndTime = DateTime.UtcNow;
                stepContext.Exception = ex;

                _logger.LogError(ex, "Saga step {StepName} failed, XID: {Xid}", stepName, sagaContext.Xid);
                
                return new SagaStepResult
                {
                    Success = false,
                    Exception = ex,
                    StepContext = stepContext
                };
            }
        }

        /// <summary>
        /// 执行补偿
        /// </summary>
        /// <param name="stepContext">步骤上下文</param>
        /// <returns>补偿结果</returns>
        protected async Task<bool> CompensateAsync(SagaStepContext stepContext)
        {
            if (stepContext.CompensationAction == null)
            {
                return true;
            }

            try
            {
                await stepContext.CompensationAction(stepContext.Result);
                stepContext.Status = SagaStepStatus.Compensated;
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Saga step compensation failed, StepId: {StepId}", stepContext.StepId);
                stepContext.Status = SagaStepStatus.CompensationFailed;
                return false;
            }
        }
    }
}